﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace CatClient.Common
{
    internal class ConcurrentList<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IList, ICollection
    {
        private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);

        private readonly List<T> _list = new List<T>();

        private object _syncRoot;

        public T this[int index]
        {
            get
            {
                return this.ReadLock<T>(() => this._list[index]);
            }
            set
            {
                this.WriteLock<T>(() => this._list[index] = value);
            }
        }

        public int Count
        {
            get
            {
                return this.ReadLock<int>(() => this._list.Count);
            }
        }

        object ICollection.SyncRoot
        {
            get
            {
                if (this._syncRoot == null)
                {
                    Interlocked.CompareExchange<object>(ref this._syncRoot, new object(), null);
                }
                return this._syncRoot;
            }
        }

        bool ICollection.IsSynchronized
        {
            get
            {
                return false;
            }
        }

        bool ICollection<T>.IsReadOnly
        {
            get
            {
                return false;
            }
        }

        object IList.this[int index]
        {
            get
            {
                return this[index];
            }
            set
            {
                if (value is T)
                {
                    this[index] = (T)((object)value);
                }
            }
        }

        bool IList.IsReadOnly
        {
            get
            {
                return false;
            }
        }

        bool IList.IsFixedSize
        {
            get
            {
                return false;
            }
        }

        public void Add(T item)
        {
            this.WriteLock(delegate
            {
                this._list.Add(item);
            });
        }

        void ICollection<T>.Add(T item)
        {
            this.Add(item);
        }

        public int IndexOf(T item)
        {
            return this.ReadLock<int>(() => this._list.IndexOf(item));
        }

        public void Insert(int index, T item)
        {
            this._list.Insert(index, item);
        }

        public void Clear()
        {
            this.WriteLock(delegate
            {
                this._list.Clear();
            });
        }

        public bool Contains(T item)
        {
            return this.ReadLock<bool>(() => this._list.Contains(item));
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            this.ReadLock(delegate
            {
                this._list.CopyTo(array, arrayIndex);
            });
        }

        public bool Remove(T item)
        {
            return this.WriteLock<bool>(() => this._list.Remove(item));
        }

        public void Dispose()
        {
            ReaderWriterLockSlim expr_06 = this._lock;
            if (expr_06 == null)
            {
                return;
            }
            expr_06.Dispose();
        }

        public IEnumerator<T> GetEnumerator()
        {
            return this.ReadLock<List<T>.Enumerator>(() => this._list.ToList<T>().GetEnumerator());
        }

        private TResult ReadLock<TResult>(Func<TResult> func)
        {
            this._lock.EnterReadLock();
            TResult result;
            try
            {
                result = func();
            }
            finally
            {
                if (this._lock.IsReadLockHeld)
                {
                    this._lock.ExitReadLock();
                }
            }
            return result;
        }

        private void ReadLock(Action func)
        {
            this._lock.EnterReadLock();
            try
            {
                func();
            }
            finally
            {
                if (this._lock.IsReadLockHeld)
                {
                    this._lock.ExitReadLock();
                }
            }
        }

        private TResult WriteLock<TResult>(Func<TResult> func)
        {
            this._lock.EnterWriteLock();
            TResult result;
            try
            {
                result = func();
            }
            finally
            {
                if (this._lock.IsWriteLockHeld)
                {
                    this._lock.ExitWriteLock();
                }
            }
            return result;
        }

        private void WriteLock(Action func)
        {
            this._lock.EnterWriteLock();
            try
            {
                func();
            }
            finally
            {
                if (this._lock.IsWriteLockHeld)
                {
                    this._lock.ExitWriteLock();
                }
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        void ICollection.CopyTo(Array array, int index)
        {
            this.ReadLock(delegate
            {
                Array.Copy(this._list.ToArray(), 0, array, index, this._list.Count);
            });
        }

        void IList<T>.RemoveAt(int index)
        {
            this.WriteLock<bool>(() => this.Remove(this[index]));
        }

        int IList.Add(object value)
        {
            if (value is T)
            {
                this.Add((T)((object)value));
            }
            return this.Count - 1;
        }

        bool IList.Contains(object value)
        {
            return value is T && this.Contains((T)((object)value));
        }

        int IList.IndexOf(object value)
        {
            if (value is T)
            {
                return this.IndexOf((T)((object)value));
            }
            return -1;
        }

        void IList.Insert(int index, object value)
        {
            if (value is T)
            {
                this.Insert(index, (T)((object)value));
            }
        }

        void IList.Remove(object value)
        {
            if (value is T)
            {
                this.Remove((T)((object)value));
            }
        }

        void IList.RemoveAt(int index)
        {
            this.WriteLock<bool>(() => this.Remove(this[index]));
        }
    }
}
